package com.crypt.properties.startup;

import com.crypt.properties.CryptProperties;
import com.crypt.properties.algorithm.AbstractCryptAlgorithm;
import com.crypt.properties.algorithm.CryptAlgorithm;
import com.crypt.properties.factory.CryptFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

import java.util.*;

public class Startup {
    // exclude system source
    private static final List<String> excludePropertySources = Arrays.asList("systemProperties", "systemEnvironment");

    /**
     * load all decrypt algorithm
     */
    public static void load() {
        ServiceLoader<CryptAlgorithm> serviceLoader = ServiceLoader.load(CryptAlgorithm.class);
        for (CryptAlgorithm cryptAlgorithm : serviceLoader) {
            // load class only
            String alg = cryptAlgorithm.getAlg();
            if (alg == null || alg.length() == 0 || alg.trim().length() == 0) {
                continue;
            }
            if (cryptAlgorithm instanceof AbstractCryptAlgorithm) {
                continue;
            }
            CryptFactory.instance().addCryptAlgorithm(alg, cryptAlgorithm);
        }
    }

    /**
     * exclude system properties
     *
     * @param environment env
     * @return true / false
     */
    private static boolean isExclude(ConfigurableEnvironment environment) {
        Boolean isExclude = environment.getProperty(CryptProperties.exclude, Boolean.class);
        if (isExclude == null) {
            return true;
        }
        return isExclude;
    }

    /**
     * copy all properties
     *
     * @param environment env properties
     * @return properties
     */
    public static Map<String, Object> copyProperties(ConfigurableEnvironment environment) {
        Map<String, Object> propertiesMap = new HashMap<>();
        MutablePropertySources propertySources = environment.getPropertySources();
        for (PropertySource<?> propertySource : propertySources) {
            if (propertySource instanceof MapPropertySource) {
                MapPropertySource source = (MapPropertySource) propertySource;
                String sourceName = source.getName();
                if (excludePropertySources.contains(sourceName) && isExclude(environment)) {
                    continue;
                }
                Map<String, Object> map = source.getSource();
                for (String key : map.keySet()) {
                    Object value = map.get(key);
                    propertiesMap.put(key, value);
                }
            }
        }
        return Collections.unmodifiableMap(propertiesMap);
    }
}
